#include "Eon_Editor.h"
#include "libmsg.h"
/*============================================================================*
 *                                  Local                                     *
 *============================================================================*/
struct _Eon_Editor
{
	Ender_Element *layout;
	Eon_Window *win;
	Eina_List *plugins;
	Libmsg_Subject subject;
};

typedef struct _Eon_Editor_Plugin
{
	Eon_Editor_Plugin_Descriptor *descriptor;
	void *data;
} Eon_Editor_Plugin;

typedef struct _Eon_Editor_Observer_Data
{
	Eon_Editor *thiz;
	Eon_Editor_Cb cb;
	void *data;
} Eon_Editor_Observer_Data;

static void _libmsg_observer(Libmsg_Subject *s, const char *event_name,
		void *event_data, void *data)
{
	Eon_Editor_Observer_Data *d = data;

	d->cb(d->thiz, event_data, d->data);
}
/*============================================================================*
 *                                 Global                                     *
 *============================================================================*/
Eon_Editor * _editor = NULL;
const void * EON_EDITOR_EVENT_ELEMENT_ADD = "element_add";
const void * EON_EDITOR_EVENT_ELEMENT_SELECT = "element_select";

Eon_Editor * eon_editor_setup(Eon_Backend *backend, unsigned int width, unsigned int height)
{
	Eon_Editor *thiz;
	Eina_List *l;
	Eon_Editor_Plugin *p;

	if (_editor) return _editor;

	thiz = calloc(1, sizeof(Eon_Editor));
	libmsg_subject_setup(&thiz->subject);
	thiz->layout = eon_stack_new();
	eon_stack_last_expand_set(thiz->layout, EINA_TRUE);
	thiz->win = eon_window_new(backend, thiz->layout, width, height);
	_editor = thiz;
	/* register every plugin in theory */
	/* register the core plugins */
	/* drawing area */
	eon_editor_drawing_area_init();
	eon_editor_properties_init();
	eon_editor_creator_init();
	/* creator */
	/* property list */

	/* for every plugin call the setup, in case of a gui also add the
	 * root element to the layout
	 */
	EINA_LIST_FOREACH(thiz->plugins, l, p)
	{
		Eon_Editor_Plugin_Descriptor *d = p->descriptor;

		/* call the setup */
		if (d->setup)
		{
			if (!d->setup(thiz, p->data))
				continue;
		}
		if (d->type == EON_EDITOR_PLUGIN_GUI)
		{
			Eon_Editor_Plugin_Gui *gui = d->type_data;
			Ender_Element *e;

			e = gui->root_get(p->data);
			if (e)
			{
				eon_layout_child_add(thiz->layout, e);
			}
		}
	}

	return thiz;
}
/*============================================================================*
 *                                   API                                      *
 *============================================================================*/
EAPI void eon_editor_plugin_register(Eon_Editor_Plugin_Descriptor *desc, void *data)
{
	Eon_Editor_Plugin *ep;

	ep = calloc(1, sizeof(Eon_Editor_Plugin));
	ep->descriptor = desc;
	ep->data = data;
	_editor->plugins = eina_list_append(_editor->plugins, ep);
}

EAPI void eon_editor_element_add(Eon_Editor *thiz, Ender_Element *e)
{
	Eon_Editor_Event_Element_Add ev;

	ev.e = e;
	libmsg_subject_notify(&thiz->subject, EON_EDITOR_EVENT_ELEMENT_ADD, &ev);
}

EAPI void eon_editor_element_select(Eon_Editor *thiz, Ender_Element *e)
{
	Eon_Editor_Event_Element_Select ev;

	ev.e = e;
	libmsg_subject_notify(&thiz->subject, EON_EDITOR_EVENT_ELEMENT_SELECT, &ev);
}

EAPI void eon_editor_event_register(Eon_Editor *thiz, const void *event, Eon_Editor_Cb cb, void *data)
{
	Eon_Editor_Observer_Data *odata;

	odata = calloc(1, sizeof(Eon_Editor_Observer_Data));
	odata->thiz = thiz;
	odata->cb = cb;
	odata->data = data;

	libmsg_subject_observer_add(&thiz->subject, event, _libmsg_observer, odata);
}
